
	/************************************************************************************************

		Liquid runtime

		Introspection:
			b		isAugmented											(v)
			b		isArray													(v)
			b		isArrayLike											(v)
			b		isBoolean												(v)
			b		isClass													(v)
			b		isDate													(v)
			b		isError													(v)
			b		isFunction											(v)
			b		isInteger												(v)
			b		isInterface											(v)
			b		isModule												(v)
			b		isNumber												(v)
			b		isObject												(v)
			b		isRegExp												(v)
			b		isString												(v)
			b 	isSubTypeOf											(type, type2)
			b 	isSuperTypeOf										(type, type2)

		System messages:
			mod	message													(id)
			mod	message													(id, msg*, locale*)
			msg	message													(id, params*)

		Errors:
			mod	error														(name, super*, msg*)
					throwError											(e, cx*, args*)

		Debug:
			mod	validator												(id, rule)
			mod	validate												(v, id, param*, error*)

		Validation rules:
			Numbers:
				n, n+, n++, N, N+, N++
				i, i+, i++, I, I+, I++
			Others:
				al, b, class, e, enum, interface, f, o, qid, re, url, s, s+
			Composite:
				al|i, al|s, b|f, b|n+, b|s+, e|f, f|s+, i+|s+, n+|s+, re|s+

		Private (micro-lang):
			a		__mlng_object_name						(obj)

			s		__mlng_function_name					(fn)
			s		__mlng_function_body					(fn)

			a		__mlng_array_unique						(ar, options)

	************************************************************************************************/

	var jsl																= {}
	jsl.__name														= "jsl"
	jsl.__magic														= "J345NN48H756PQ56"
	jsl.__v																= "[jsl-v]"
	jsl.__dbg															= "[jsl-d]"

	jsl.__go															= this
	jsl.__f																= function(){}
	jsl.__eval														= function(s) { return eval.call(jsl.__go, s) }
	jsl.__errs														= {}
	jsl.__tmp															= {}
  jsl.__re  			   										= {}

  jsl.__re.id  													= /^[a-zA-Z_\$][\w\$]*$/
  jsl.__re.qid 													= /^[a-zA-Z_\$][\w\$]*(\.[a-zA-Z_\$][\w\$]*)*$/

	jsl.__signatures											= {}
	jsl.__signatures["jsl.Class"]					= "A7ISX0CC0K1PZN3J"

  jsl.__objs														= {}
  jsl.__msgs 														= {}
  jsl.__vrules                      	  = {}

	//in case of error before is created the jsl module
	//-------------------------------------------------------------------------------
	jsl.name = function() { return "jsl" }

	//Introspection:
	//-------------------------------------------------------------------------------
	jsl.isAugmented = function(v) {
		try {//!
			if(arguments.length !== 1)	throw jsl.ParamError()//!
			return v != null && !!v.__augmented
		}
		catch(e) {
  		jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.isArray = function(v) {
		try {//!
			if(arguments.length !== 1)	throw jsl.ParamError()//!
			return v instanceof Array
		}
		catch(e) {
  		jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.isArrayLike = function(v) {
		try {
			var rv
			//!
			if(arguments.length !== 1)	throw jsl.ParamError()//!

			rv = v instanceof Array

			if(!rv)
				rv = jsl.isObject(v) && v.length >= 0 && jsl.isInteger(v.length) && !jsl.isString(v) && !jsl.isFunction(v)

			return rv
		}
		catch(e) {
  		jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.isBoolean = function(v) {
		try {//!
			if(arguments.length !== 1)	throw jsl.ParamError()//!
			return typeof v === "boolean" || v instanceof Boolean
		}
		catch(e) {
  		jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.isClass = function(v) {
		try {//!
			if(arguments.length !== 1)	throw jsl.ParamError()//!
			return v instanceof Function && v.__signature === jsl.__signatures["jsl.Class"]
		}
		catch(e) {
  		jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.isDate = function(v) {
		try {//!
			if(arguments.length !== 1)	throw jsl.ParamError()//!
			return v instanceof Date
		}
		catch(e) {
  		jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.isError = function(v) {
		try {//!
			if(arguments.length !== 1)	throw jsl.ParamError()//!
			return v instanceof Error || v instanceof jsl.Error
		}
		catch(e) {
  		jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.isFunction = function(v) {
		try {//!
			if(arguments.length !== 1)	throw jsl.ParamError()//!
			//v instanceof Function
			//@sys: Explorer 8 - RangeError is not instanceof Function
			//@sys: WebKit typeof /regexp/ = 'function' -> sugar syntax: /hello/("string") -> /hello/.exec("string")
			return (typeof v === "function" && !(v instanceof RegExp)) || (v instanceof Function)
		}
		catch(e) {
  		jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.isInteger = function(v) {
		try {
			var b//!
			if(arguments.length !== 1)	throw jsl.ParamError()//!

			b = (typeof v === "number" || v instanceof Number) && !isNaN(v) && isFinite(v)

			if(b)
				if(v >= -2147483648 && v <= 2147483647) b = v - ~~v === 0
				else 																		b = v - Math.floor(v) === 0

			return b
		}
		catch(e) {
  		jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.isInterface = function(v) {
		try {//!
			if(arguments.length !== 1)	throw jsl.ParamError()//!
			return v instanceof jsl.Interface
		}
		catch(e) {
  		jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.isModule = function(v) {
		try {//!
			if(arguments.length !== 1)	throw jsl.ParamError()//!
			return v instanceof jsl.Module
		}
		catch(e) {
  		jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.isNumber = function(v) {
		try {//!
			if(arguments.length !== 1)	throw jsl.ParamError()//!
			return typeof v === "number" || v instanceof Number
		}
		catch(e) {
  		jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.isObject = function(v) {
		try {//!
			if(arguments.length !== 1)	throw jsl.ParamError()//!

			//v instanceof Object
			//@sys: Firefox 3.5.6 - window instanceof Object -> false but typeof window === "object" -> true
			return v instanceof Object || (v != null && typeof v === "object")
		}
		catch(e) {
  		jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.isRegExp = function(v) {
		try {//!
			if(arguments.length !== 1)	throw jsl.ParamError()//!
			return v instanceof RegExp
		}
		catch(e) {
  		jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.isString = function(v) {
		try {//!
			if(arguments.length !== 1)	throw jsl.ParamError()//!
			return typeof v === "string" || v instanceof String
		}
		catch(e) {
  		jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.isSubTypeOf = function(type, type2) {
		try {//!
			if(arguments.length !== 2)	throw jsl.ParamError()
			jsl.validate(type	, "f", "type")
			jsl.validate(type2, "f", "type2")//!

			return type2.prototype.isPrototypeOf(type.prototype)
		}
		catch(e) {
  		jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.isSuperTypeOf = function(type, type2) {
		try {//!
			if(arguments.length !== 2)	throw jsl.ParamError()
			jsl.validate(type	, "f", "type")
			jsl.validate(type2, "f", "type2")//!

			return type.prototype.isPrototypeOf(type2.prototype)
		}
		catch(e) {
  		jsl.throwError(e, this, arguments)
		}
	}
	//Messages:
	//-------------------------------------------------------------------------------
	jsl.message = function(id, msg, locale) {
  	try {
			var rv, i, err, n, dx, m1, m2, s1, s2, lc
			//!
			if(!arguments.length  || arguments.length > 3)	throw jsl.ParamError()
			jsl.validate(id	, "s"	, "id")//!

			//1-message(id)
			//-------------------------------------------------------------------------------
			if(arguments.length === 1) {
				//if(jsl.Locale) -> wrong (while the module is loading the [t] validator composes error messages)
				if(jsl.__libs.locale != true)	rv = jsl.__msgs[jsl.Locale.current() + "." + id] || jsl.__msgs[id] || null
				else 													rv = jsl.__msgs[id] || null
			}

			//2-message(id, params*)
			//-------------------------------------------------------------------------------
			else if(msg instanceof Array) {//!
				if(arguments.length === 3)	throw jsl.ParamError()//!

				i		= 0
				dx	= 0
				rv	=	jsl.message(id) || id
				rv 	= rv.replace(/(!*)\$(\??)/g, function(tk, g1, g2) {
					var c, l, s

					c = g1 && g1.slice(0, ~~(g1.length / 2)) || ""
					l = g1 && g1.length % 2

					if(!l && g2) {//!
						if(n != null) err = true//!
						n		= i
						dx  = arguments[3] + dx + c.length
						s		= ""
					}
					else if(g2)	s = "$?"
					else				s = l ? "$" : (i < msg.length ? msg[i++] : tk)

					if(n == null) dx += (c + s).length - tk.length
					return c + s
				})

				//!
				if(err) throw jsl.ParamError("BadNumberOf" , [ "msg", "$?" ])
				if(msg.length !== n && msg.length !== i)	throw jsl.ParamError("BadArrayLength:params")//!

				if(msg.length === n)
					rv = rv.slice(0, dx)
			}

			//3-message(id, msg, locale*)
			//-------------------------------------------------------------------------------
			else {//!
				jsl.validate(id	, "qid", "id")
				jsl.validate(msg, "s+", "msg")
				if(arguments.length === 3)	jsl.validate(locale, "sr/^\\w+(\\-\\w+)?$", "locale")

				s1 	= msg.replace(/(!!)+/g, "").replace(/!\$/g, "_")
				m1 	= s1.match(/\$\?/g)
				m1	= m1 ? m1.length : 0
				if(m1 > 1)	throw jsl.ParamError("BadNumberOf:msg:$?")

				s2 = jsl.__msgs[id]
				if(s2) {

					s2 	= s2.replace(/(!!)+/g, "").replace(/!\$/g, "_")
					m2 	= s2.match(/\$\?/g)
					m2	= m2 ? m2.length : 0
					if(m1 !== m2)	throw jsl.ParamError("BadNumberOf:msg:$?")

					m1 	= s1.match(/\$/g)
					m1 	= m1 ? m1.length : 0

					m2 = s2.match(/\$/g)
					m2 = m2 ? m2.length : 0

					if(m1 !== m2)	throw jsl.ParamError("BadNumberOf:msg:$")
				}//!

				if(locale) {
					if(locale.indexOf("-") === -1) lc = locale + "-" + locale
					else lc = locale
					jsl.__msgs[lc.toLowerCase() + "." + id] = msg + ""
				}

				if(!jsl.__msgs[id]) jsl.__msgs[id] = msg + ""
				rv = jsl
			}

			return rv
  	}
  	catch(e) {
  		jsl.throwError(e, this, arguments)
  	}
  }
	//Errors:
	//-------------------------------------------------------------------------------
	jsl.error = function(name, $super, msg) {
		try {
      var error

			//!
      if(!arguments.length || arguments.length > 3)	throw jsl.ParamError()
			jsl.validate(name, "s+", "name")
			if(jsl.__errs[name])				throw jsl.ParamError("AlreadyDefined:name")
			if(arguments.length >= 2) 	jsl.validate($super, "f", "super")
 	    if(arguments.length >= 2 && $super !== jsl.Error && !jsl.isSubTypeOf($super, jsl.Error)) throw jsl.ParamError("BadType:super:jsl.Error")
			if(arguments.length === 3) 	jsl.validate(msg, "s+", "msg")
			//!

			//-------------------------------------------------------------------------------
			error = function(p1, p2, p3) {
				try {
					var n, isA, er

					isA = jsl.isArray(p2)//!
					if(arguments.length > (isA ? 3 : 2))			throw jsl.ParamError()
					if(arguments.length 			&& p1 == null)	throw jsl.ParamError("NullValue:msg")
					if(arguments.length >= 2	&& p2 == null)	throw jsl.ParamError("NullValue:" + (isA ? "params" : "cause"))
					if(arguments.length == 3 	&& p3 == null)	throw jsl.ParamError("NullValue:cause")
					if(isA && jsl.isError(p1))								throw jsl.ParamError("BadType:msg:!jsl.Error")//!

					if(this instanceof arguments.callee && !this.__created) {

						this.__created		= true
						this.constructor 	= arguments.callee

						n = arguments.length
						if(n)
							if(n === 1)							this.message(p1)
							else if(n === 2 && isA)	this.message(p1, p2)
							else if(isA)						this.message(p1, p2).cause(p3)
							else if(n === 2)				this.message(p1).cause(p2)

						//@sys: Firefox console - from the console a liquid error is displayed in a
						//												bad form: "Error: function [message] converted into a string"
						er = this
						this.message.toString = function() { return er + "" }
						return this
          }
					else {
						n = arguments.length
						if(!n)						return new error
						else if(n === 1)	return new error(p1)
						else if(n === 2)	return new error(p1, p2)
						else 							return new error(p1, p2, p3)
					}
				}
				catch(e) {
		 			jsl.throwError(e, jsl, arguments)
				}
			}
			//-------------------------------------------------------------------------------
      error.prototype							= ($super || jsl.Error)()
			error.prototype.__name			= "jsl." + name
			error.prototype.__dmessage 	= jsl.__msgs["e." + msg] || msg
			delete error.prototype.__created

			//-------------------------------------------------------------------------------
			jsl[name] 				= error
			jsl.__errs[name]	= true
			return error
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.throwError = function(e, cx, args) {
  	try {
  		var e2

			//!
			if(!arguments.length)	throw jsl.ParamError()
			if(arguments.length >= 2)
  			if(typeof cx === "string" ? arguments.length > 3 : arguments.length !== 3)	throw jsl.ParamError()
			//!

			if(arguments.length === 1)			e2 = jsl.Error(e)
			else if(arguments.length === 2)	e2 = jsl.Error(e).trace(cx)
			else														e2 = jsl.Error(e).trace(cx, args)
  	}
  	catch(e3) {
 			jsl.throwError(e3, this, arguments)
  	}
		throw e2
  }

	//-------------------------------------------------------------------------------
	jsl.validator = function(id, rule) {
		try {
			//!
			if(arguments.length !== 2)	throw jsl.ParamError()
			if(id == null)							throw jsl.ParamError("NullValue:			id")
			if(!jsl.isString(id))				throw jsl.ParamError("BadType:				id:string")
			if(!id.length)							throw jsl.ParamError("EmptyString:		id")
			if(this.__vrules[id])				throw jsl.ParamError("AlreadyDefined:	id")
			if(rule == null)						throw jsl.ParamError("NullValue:			rule")
			if(!jsl.isFunction(rule))		throw jsl.ParamError("BadType:				rule:function")//!

			this.__vrules[id] = rule
			return this
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	//!
	//-------------------------------------------------------------------------------
	jsl.validate = function(v, rule, param, error) {
		try {
			//iparams -> inline params
			var params, id, idx, iparams, re, dt, s

			if(arguments.length < 2 || arguments.length > 4)	throw jsl.ParamError()
			if(rule == null)																	throw jsl.ParamError("NullValue:		rule")
			if(!jsl.isString(rule))														throw jsl.ParamError("BadType:			rule:string")
			if(!rule.length)																	throw jsl.ParamError("EmptyString:	rule")

			id 	= rule.match(/^[^\[\(\/\)\]]+/)[0]
			idx = rule.search(/\[|\(/)

			if(!this.__vrules[id])	throw jsl.ParamError("NotDefined", ["rule(" + id + ")"])

			if(idx !== -1 && rule.charAt(id.length) !== "/") {
				if(rule.search(/(\]|\))$/) === -1)	throw jsl.ParamError("BadSyntax", ["rule(" + id + ")"])
				s 	= rule.slice(idx + 1, -1)
				re 	= /[^,\[(]+[(\[][^)\]]*[)\]]|[^,]+/g

				iparams = []
				while((dt = re.exec(s)))
					iparams.push(dt[0])
			}

			//tollerate an error = null. This is used in the jsl.Object factory at the clone method when is called at
			//the factory initialization. Inside the method, jsl.MisuseError is not yet defined
			if(error != null)
				if(error !== Error && !Error.prototype.isPrototypeOf(error.prototype))
																											throw jsl.ParamError("BadType:error:Error")

			params 		= Array.prototype.slice.call(arguments)
			params[2] = arguments.length === 2 ? params[1] : param
			params[3] = error ? error : jsl.ParamError

			if(idx !== -1)
				params[4] = iparams
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}

		this.__vrules[id].apply({}, params)
		return this
	}
	//!

	/************************************************************************************************
	*
	* Private
	*
	************************************************************************************************/

	//Private micro-lang runtime
  //-------------------------------------------------------------------------------
	jsl.__mlng_object_name = function(obj) {
		try {
 			var name

			//@sys: Firefox 4 - Error.name is undefined. In other error type is all normal
			//			ex: SyntaxError,name = "SyntaxError"
    	if(obj.__name)								name = obj.__name
    	else	if(jsl.isArray(obj))		name = "Array"
			else	if(jsl.isBoolean(obj))	name = "Boolean"
			else	if(jsl.isDate(obj))			name = "Date"
			else	if(jsl.isError(obj))		name = obj.name || "Error"
			else	if(jsl.isFunction(obj))	name = jsl.__mlng_function_name(obj)
			else	if(jsl.isNumber(obj))		name = "Number"
			else	if(jsl.isRegExp(obj))		name = "RegExp"
			else	if(jsl.isString(obj))		name = "String"
			else													name = "Object"

			return name
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.__mlng_array_unique = function(ar, options) {
		try {
			var a, b, l, l2, rv, rule

			rv 		= []
			rule 	= options && options.rule

			//Right
			//-----------------------------------------------------------------------
			if(options && options.right)
				for(a = ar.length - 1; a >= 0; a--) {

					for(b = 0, l2 = rv.length; b < l2; b++)
						if(rule ? !rule(ar[a], rv[b]) : ar[a] === rv[b])
							break

					if(b === l2)
						rv.unshift(ar[a])
				}
			//Left
			//-----------------------------------------------------------------------
			else
				for(a = 0, l = ar.length; a < l; a++) {

					for(b = 0, l2 = rv.length; b < l2; b++)
						if(rule ? !rule(ar[a], rv[b]) : ar[a] === rv[b])
							break

					if(b === l2)
						rv[b] = ar[a]
				}

			return rv
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.__mlng_function_name = function(f) {
		try {
			var txt, name

			if(!f.__name) {
				txt		= Function.prototype.toString.call(f)
				txt 	= txt.replace(/\/\*(?:[\s\S])*?\*\//g, "")
				txt 	= txt.replace(/\/\/.*\n/g, "")
				txt 	= txt.replace(/[\n\s]+/g, "")
				name	= txt.match(/[\s\S]*?function([^(]*)/)[1] || "fn"
			}
			else
				name = f.__name

			return name
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.__mlng_function_body = function(f) {
		try {
			var txt, re, ix, ix2, body

			//no cache -> it modify a not augmented object
			re		= /("(?:\\.|[^"\\])*")|('(?:\\.|[^'\\])*')|(\/\*(?:[\s\S])*?\*\/)|(\/\/[^\n]*)|(\/(?:\\.|[^\/\\])*\/)/g
			txt		= Function.prototype.toString.call(f)
			txt		= txt.replace(re, function(s, g1, g2, g3, g4, g5) { return g3 || g4 ? "" : s })
			ix		= txt.indexOf("{")
			ix2		= txt.lastIndexOf("}")
			body	= ix !== -1 && ix2 !== -1 ? txt.slice(ix + 1, ix2) : ""

			return body
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}